/*     */ package com.zimbra.cs.redolog.logger;
/*     */ 
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.redolog.RedoLogInput;
/*     */ import com.zimbra.cs.redolog.op.RedoableOp;
/*     */ import java.io.EOFException;
/*     */ import java.io.File;
/*     */ import java.io.IOException;
/*     */ import java.io.RandomAccessFile;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class FileLogReader
/*     */ {
/*     */   private FileHeader mHeader;
/*     */   private boolean mHeaderRead;
/*     */   private File mFile;
/*     */   private RandomAccessFile mRAF;
/*     */   private RedoLogInput mIN;
/*     */   private boolean mReadOnly;
/*     */   private long mFileSizeAtOpen;
/*     */   private long mLastOpStartOffset;
/*     */   
/*     */   public FileLogReader(File logfile)
/*     */   {
/*  56 */     this(logfile, false);
/*     */   }
/*     */   
/*     */   public FileLogReader(File logfile, boolean writable) {
/*  60 */     this.mHeader = new FileHeader();
/*  61 */     this.mHeaderRead = false;
/*  62 */     this.mFile = logfile;
/*  63 */     this.mReadOnly = (!writable);
/*     */   }
/*     */   
/*     */   public synchronized void open() throws IOException {
/*  67 */     this.mRAF = new RandomAccessFile(this.mFile, this.mReadOnly ? "r" : "rw");
/*  68 */     this.mIN = new RedoLogInput(this.mRAF, this.mFile.getPath());
/*  69 */     this.mHeader.read(this.mRAF);
/*  70 */     this.mHeaderRead = true;
/*  71 */     this.mFileSizeAtOpen = this.mRAF.length();
/*     */   }
/*     */   
/*     */   public synchronized void close() throws IOException {
/*  75 */     this.mRAF.close();
/*     */   }
/*     */   
/*     */   public synchronized FileHeader getHeader() throws IOException {
/*  79 */     if (this.mHeaderRead) {
/*  80 */       return this.mHeader;
/*     */     }
/*  82 */     open();
/*  83 */     close();
/*  84 */     return this.mHeader;
/*     */   }
/*     */   
/*     */   public synchronized RedoableOp getNextOp() throws IOException {
/*  88 */     long pos = this.mRAF.getFilePointer();
/*  89 */     if (pos == this.mFileSizeAtOpen)
/*     */     {
/*  91 */       return null;
/*     */     }
/*     */     
/*  94 */     boolean first = true;
/*  95 */     long currPos = pos;
/*     */     try
/*     */     {
/*  98 */       RedoableOp op = RedoableOp.deserializeOp(this.mIN);
/*  99 */       this.mLastOpStartOffset = currPos;
/* 100 */       if (!first) {
/* 101 */         String msg = String.format("Skipped bad bytes in redolog %s; resuming at offset 0x%08x after skipping %d bytes", new Object[] { this.mFile.getAbsolutePath(), Long.valueOf(currPos), Long.valueOf(currPos - pos) });
/*     */         
/*     */ 
/* 104 */         ZimbraLog.redolog.warn(msg);
/*     */       }
/* 106 */       return op;
/*     */     } catch (IOException e) {
/* 108 */       for (;;) { if ((e instanceof EOFException))
/* 109 */           throw e;
/* 110 */         if (first) {
/* 111 */           String msg = String.format("Error while parsing redolog %s, offset=0x%08x; bad bytes will be skipped", new Object[] { this.mFile.getAbsolutePath(), Long.valueOf(pos) });
/*     */           
/*     */ 
/* 114 */           ZimbraLog.redolog.warn(msg, e);
/*     */         }
/*     */         
/* 117 */         first = false;
/*     */         
/* 119 */         this.mRAF.seek(currPos + 1L);
/* 120 */         if (!searchInRAF("ZMREDO".getBytes())) break;
/* 121 */         currPos = this.mRAF.getFilePointer();
/*     */       }
/* 123 */       String msg = String.format("Found %d junk bytes from offset 0x%08x to end of file, in redolog %s", new Object[] { Long.valueOf(this.mFileSizeAtOpen - pos), Long.valueOf(pos), this.mFile.getAbsolutePath() });
/*     */       
/*     */ 
/* 126 */       throw new IOException(msg);
/*     */     }
/*     */   }
/*     */   
/*     */   public synchronized long getSize() throws IOException
/*     */   {
/* 132 */     return this.mRAF.length();
/*     */   }
/*     */   
/*     */   public synchronized long position() throws IOException {
/* 136 */     return this.mRAF.getFilePointer();
/*     */   }
/*     */   
/*     */   public synchronized long getLastOpStartOffset() throws IOException {
/* 140 */     return this.mLastOpStartOffset;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void truncate(long size)
/*     */     throws IOException
/*     */   {
/* 150 */     if (size < this.mRAF.length()) {
/* 151 */       this.mRAF.setLength(size);
/* 152 */       FileHeader hdr = getHeader();
/* 153 */       hdr.setFileSize(size);
/* 154 */       hdr.write(this.mRAF);
/* 155 */       this.mRAF.seek(size);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private boolean searchInRAF(byte[] pattern)
/*     */     throws IOException
/*     */   {
/* 165 */     int viewSize = 4096;
/* 166 */     if (pattern.length > viewSize)
/* 167 */       return false;
/* 168 */     byte[] view = new byte[viewSize * 2];
/* 169 */     long rafPos = this.mRAF.getFilePointer();
/* 170 */     long viewBaseOffset = rafPos - rafPos % viewSize;
/* 171 */     this.mRAF.seek(viewBaseOffset);
/* 172 */     int startOffset = (int)(rafPos - viewBaseOffset);
/*     */     
/* 174 */     boolean atFileEnd = false;
/*     */     int bytesRead;
/* 176 */     while ((!atFileEnd) && ((bytesRead = this.mRAF.read(view, 0, view.length)) != -1) && 
/* 177 */       (bytesRead >= pattern.length))
/*     */     {
/* 179 */       atFileEnd = viewBaseOffset + bytesRead >= this.mFileSizeAtOpen;
/* 180 */       if (atFileEnd)
/* 181 */         bytesRead = (int)(this.mFileSizeAtOpen - viewBaseOffset);
/* 182 */       int endOffset = Math.min(view.length, bytesRead);
/* 183 */       int matchAt = searchByteArray(view, startOffset, endOffset, pattern);
/* 184 */       if (matchAt != -1) {
/* 185 */         this.mRAF.seek(viewBaseOffset + matchAt);
/* 186 */         return true;
/*     */       }
/*     */       
/* 189 */       viewBaseOffset += viewSize;
/* 190 */       this.mRAF.seek(viewBaseOffset);
/* 191 */       startOffset = 0;
/*     */     }
/*     */     
/* 194 */     this.mRAF.seek(rafPos);
/* 195 */     return false;
/*     */   }
/*     */   
/*     */ 
/*     */   private static int searchByteArray(byte[] searchIn, int startOffset, int endOffset, byte[] pattern)
/*     */   {
/* 201 */     int len = pattern.length;
/* 202 */     endOffset = Math.min(endOffset, searchIn.length);
/* 203 */     byte firstByte = pattern[0];
/* 204 */     int i = startOffset;
/* 205 */     int lastIndex = endOffset - len;
/* 206 */     while (i < lastIndex) {
/* 207 */       while ((searchIn[i] != firstByte) && (i < lastIndex)) {
/* 208 */         i++;
/*     */       }
/* 210 */       if (i >= lastIndex)
/*     */         break;
/* 212 */       boolean matches = true;
/* 213 */       for (int j = 1; j < len; j++) {
/* 214 */         if (searchIn[(i + j)] != pattern[j]) {
/* 215 */           matches = false;
/* 216 */           break;
/*     */         }
/*     */       }
/* 219 */       if (matches) {
/* 220 */         return i;
/*     */       }
/* 222 */       i++;
/*     */     }
/* 224 */     return -1;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/redolog/logger/FileLogReader.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */